package com.freewater.javabase.demo.softreference;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

public class SoftReferenceTest {

    public static void main(String[] args) {
        System.out.println("<< Calling getMethodCall >>");
        getMethodCall();
        System.out.println("<< Calling referenceQueue >>");
        referenceQueue();
        System.out.println("<< Calling referenceQueueUseWeakHashMap >>");
        referenceQueueUseWeakHashMap();
    }

    // Java program to show the demonstration
    // of get() method of SoftReference Class
    static void getMethodCall() {
        // creating a strong object of MyClass
        MyClass obj = new MyClass();
        SoftReference<MyClass> sobj = new SoftReference<>(obj);
        System.out.println("-> Calling Display Function using strong object:");
        obj.display();
        System.out.println("-> Object set to null");
        obj = null;
        // Calling the get() method
        obj = sobj.get();
        System.out.println("-> Calling Display Function after retrieving from soft Object");
        obj.display();
    }

    static void referenceQueue() {
        final int OneMB = 1024 * 1024;// 1MB字节数
        final Object value = new Object();
        final Map<Object, Object> map = new HashMap<>();
        final ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();

        // 启动线程监听内存回收
        Thread thread = new Thread(() -> {
            int cnt = 0;
            try {
                WeakReference<byte[]> k;
                while ((k = (WeakReference<byte[]>) referenceQueue.remove()) != null) {
                    System.out.println(++cnt + "回收了：" + k);
                    map.remove(k);// 使用WeakHashMap也可以达到回收后删除的目的

                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread.setDaemon(true); // ReferenceQueue.remove方法会阻塞，所以设置此线程为daemon，随主线程一并关闭
        thread.start();

        // 开始向map中放入10000*1MB数据，给内存施加压力，迫使jvm触发gc
        for (int i = 0; i < 10000; i++) {
            WeakReference<byte[]> ref = new WeakReference<>(new byte[OneMB], referenceQueue);
            map.put(ref, value);
        }
        System.out.println("HashMap size: " + map.size());
    }

    static void referenceQueueUseWeakHashMap() {
        final int OneMB = 1024 * 1024;// 1MB字节数
        final Object value = new Object();
        final WeakHashMap<Object, Object> map = new WeakHashMap<>();
        final ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
        // 开始向map中放入10000*1MB数据，给内存施加压力，迫使jvm触发gc
        for (int i = 0; i < 10000; i++) {
            WeakReference<byte[]> ref = new WeakReference<>(new byte[OneMB], referenceQueue);
            map.put(ref, value);
        }
        System.out.println("WeakHashMap size: " + map.size());
    }

    static class MyClass {
        void display() {
            System.out.println("Display Function invoked ...");
        }
    }
}
